package app.util.image.calc
{
	import flash.display.*;
	
	public class BinaryBitmapData
	{		
		//Store boolean
		private var data:Array;
		private var width:int;
		private var height:int;
		
		private const MARKED_COLOR:uint = 0xffffff;		//White
		private const UNMARKED_COLOR:uint = 0x000000;	//Black
		
		public static function generateFromBmp(srcData:BitmapData, threshold:Number):BinaryBitmapData
		{
			var w:int = srcData.width;
			var h:int = srcData.height;
			var b:BinaryBitmapData = new BinaryBitmapData(w, h);
			
			for(var x:int = 0; x < w; x++)
			{
				for(var y:int = 0; y < h; y++)
				{
					var gray:uint = BMPUtility.calcGrayFromColor(srcData.getPixel(x, y));
					if(gray > threshold) b.setMarked(x, y);
				}
			}
			
			return b;
		}		
		
		public function BinaryBitmapData(w:int, h:int, assignData:Boolean = true)
		{
			this.width = w;
			this.height = h;
			
			if(assignData)
			{
				clearMarked();
			}
		}
	
		public function getWidth():int { return this.width; }
		public function getHeight():int { return this.height; }
		
		public function setMarked(x:int, y:int, marked:Boolean = true):void
		{
			if(x < 0 || y < 0 || x >= this.width || y >= this.height) return;
			this.data[y * this.width + x] = marked;
		} 
		
		public function isMarked(x:int, y:int):Boolean
		{
			if(x < 0) x = 0;
			if(y < 0) y = 0;
			if(x >= this.width) x = this.width;
			if(y >= this.height) y = this.height;
			return this.data[y * this.width + x] as Boolean;
		}
		
		public function clearMarked():void
		{
			var size:int = this.width * this.height;
			this.data = new Array(size);
			
			for(var i:int = 0; i < size; i++)
			{
				this.data[i] = false;
			}	
		}
		
		public function isEmpty():Boolean
		{
			for(var i:int = 0; i < this.width; i++)
			{
				for(var j:int = 0; j < this.height; j++)
				{
					if(this.isMarked(i, j))
					{
						return false;
					}
				}
			}
			
			return true;
		}
			
		public function clone():BinaryBitmapData
		{
			var b:BinaryBitmapData = new BinaryBitmapData(this.width, this.height, false);
			b.data = this.data.concat();
			return b;
		}
		
		public function addWithColor(m:BinaryBitmapData, repeatColor:uint):BitmapData
		{
			if(m.width == this.width && m.height == this.height)
			{
				var ret:BitmapData = new BitmapData(this.width, this.height, false, UNMARKED_COLOR);
				for(var i:int = 0; i < this.width; i++)
				{
					for(var j:int = 0; j < this.height; j++)
					{
						if(this.isMarked(i, j) && !m.isMarked(i, j))
						{
							ret.setPixel(i, j, MARKED_COLOR);
						}		
						else if(!this.isMarked(i, j) && m.isMarked(i, j))
						{
							ret.setPixel(i, j, MARKED_COLOR);
						}
						else if(this.isMarked(i, j) && m.isMarked(i, j))
						{
							ret.setPixel(i, j, repeatColor);
						}
					}
				}
				
				return ret;
			}
			
			return null;
		}
		
		public function add(m:BinaryBitmapData):BinaryBitmapData
		{
			var ret:BinaryBitmapData = new BinaryBitmapData(this.width, this.height);
			for(var i:int = 0; i < this.width; i++)
			{
				for(var j:int = 0; j < this.height; j++)
				{
					if(this.isMarked(i, j) || m.isMarked(i, j))
					{
						ret.setMarked(i, j);
					}		
				}
			}
			
			return ret;
		}
		
		public function minus(m:BinaryBitmapData):BinaryBitmapData
		{
			var ret:BinaryBitmapData = new BinaryBitmapData(this.width, this.height);
			for(var i:int = 0; i < this.width; i++)
			{
				for(var j:int = 0; j < this.height; j++)
				{
					if(this.isMarked(i, j) && !m.isMarked(i, j))
					{
						ret.setMarked(i, j);
					}		
				}
			}
			
			return ret;
		}	
		
		public function equal(m:BinaryBitmapData):Boolean
		{
			for(var i:int = 0; i < this.width; i++)
			{
				for(var j:int = 0; j < this.height; j++)
				{
					if(this.isMarked(i, j) != m.isMarked(i, j))
					{
						return false;
					}		
				}
			}
			
			return true;
		}				
		
		public function intersect(m:BinaryBitmapData):BinaryBitmapData
		{
			var ret:BinaryBitmapData = new BinaryBitmapData(this.width, this.height);
			for(var i:int = 0; i < this.width; i++)
			{
				for(var j:int = 0; j < this.height; j++)
				{
					if(this.isMarked(i, j) && m.isMarked(i, j))
					{
						ret.setMarked(i, j);
					}		
				}
			}
			
			return ret;
		}	
			
		public function toBitmapData():BitmapData
		{
			var bmp:BitmapData = new BitmapData(this.width, this.height, false, UNMARKED_COLOR);
			for(var i:int = 0; i < this.width; i++)
			{
				for(var j:int = 0; j < this.height; j++)
				{
					if(this.isMarked(i, j))
					{
						bmp.setPixel(i, j, MARKED_COLOR);
					}
				}
			}
			return bmp;
		}
	}
}